package com.zgis.module.db.util;

import com.zgis.module.bas.bean.CxFld;
import com.zgis.module.bas.constant.CxConsts;
import com.zgis.module.bas.constant.CxErrors;
import com.zgis.module.bas.constant.CxKeys;
import com.zgis.module.bas.util.CxValueUtil;
import com.zgis.module.db.bean.CxUnionTable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 修改记录
 * 23-09-16	  zhengchaojun			增加排除部分列，用于 select 列，去掉排除的列
 */

/**
 * SQL工具类
 */
public class SqlUtil
{
    /**
     * 取部分字段信息（排除部分字段，不考虑别名）
     *
     * @param flds   字段列表
     * @param exCols 排除字段（fld1,fld2,fld3）
     * @return 字段信息
     */
    public static List<CxFld> getPartFieldsEx(List<CxFld> flds, String exCols)
    {
        //确定输出的字段
        if (exCols != null && exCols.length() > 0)            //排除字段
        {
            int                  fldNum   = flds.size();
            List<CxFld>          partFlds = new ArrayList<CxFld>(fldNum);
            String[]             arrCols  = exCols.split(CxConsts.defSep);
            int                  i, num   = arrCols.length;
            Map<String, Integer> map      = new HashMap<>();
            CxFld                fld;

            // 建索引
            for (i = 0; i < num; i++)
                map.put(arrCols[i], 0);

            for (i = 0; i < fldNum; i++)
            {
                fld = flds.get(i);
                if (!map.containsKey(fld.getColname()))
                    partFlds.add(fld);
            }

            return partFlds;
        }

        return flds;
    }

    /**
     * 取部分字段信息（考虑别名，有别名的需要重新申请对象）
     *
     * @param cols 字段（fld1,fld2 as fld21,fld3）
     * @param flds 字段列表
     * @return 字段信息
     * @throws Exception 异常
     */
    public static List<CxFld> getPartFields1(String cols, List<CxFld> flds) throws Exception
    {
        //确定输出的字段
        if (cols != null && cols.length() > 0)                //设置字段
        {
            //解开字段，确定需要查询的字段
            String[]    arrCols  = cols.split(CxConsts.defSep);
            int         i, num   = arrCols.length;
            String[]    arrName;
            List<CxFld> partFlds = new ArrayList<CxFld>(num);
            CxFld       fld, fld1;

            // 创建字段名到字段对象的映射
            Map<String, CxFld> fldMap = new HashMap<>();
            for (CxFld f : flds) {
                fldMap.put(f.getColname(), f);
            }

            for (i = 0; i < num; i++)
            {
                arrName = arrCols[i].split(" as ");
                fld = fldMap.get(arrName[0]);
                if (fld == null)
                    throw new Exception(arrCols[i] + " column is't exist!");

                //有别名需要重新申请对象
                if (arrName.length == 2 && arrName[1].length() > 0)
                {
                    fld1 = new CxFld();
                    fld.copy(fld1);
                    fld1.alias = arrName[1];
                }
                else
                    fld1 = fld;

                partFlds.add(fld1);
            }

            return partFlds;
        }

        return flds;
    }

    /**
     * 取部分字段名（排除部分字段，不考虑别名）
     *
     * @param flds   列字段
     * @param exCols 排除字段（fld1,fld2,fld3）
     * @return 字段名（id,***,***,**）
     */
    public static String getColsSelectEx(List<CxFld> flds, String exCols)
    {
        int                  fldNum  = flds.size();
        String[]             arrCols = exCols.split(CxConsts.defSep);
        int                  i, num  = arrCols.length;
        Map<String, Integer> map     = new HashMap<>();
        String               colname;
        String               ret     = CxKeys.id;

        // 建索引
        for (i = 0; i < num; i++)
            map.put(arrCols[i], 0);

        for (i = 0; i < fldNum; i++)
        {
            colname = flds.get(i).getColname();
            //看在不在排除的列里面
            if (!map.containsKey(colname))
            {
                ret += CxConsts.defSep + colname;
            }

        }

        return ret;
    }

    /**
     * 生成字段（SELECT flda a,fldb b FROM 格式）
     *
     * @param flds 字段信息
     * @return 查询字段字符串
     */
    public static String getColsSelect(List<CxFld> flds)
    {
        String ret = CxKeys.id;
        CxFld  fld;

        for (int i = 0, fldNum = flds.size(); i < fldNum; i++)
        {
            fld = flds.get(i);
            ret += CxConsts.defSep + fld.getColname() + (fld.alias != null ? " " + fld.alias : "");
        }

        return ret;
    }

    /**
     * 生成字段 SELECT flda a,fldb b FROM 格式，处理空间字段的数据缓存
     *
     * @return
     * @param    flds            字段列表
     */
    public static String getColsSelect(List<CxFld> flds, int dbtype)
    {
        String ret = "id";
        CxFld  fld;

        for (int i = 0, fldNum = flds.size(); i < fldNum; i++)
        {
            fld = flds.get(i);

            if (fld.getColname().equals(CxKeys.geom))
            {
                ret += "," + getGeomCol("", dbtype) + " " + CxKeys.geom;
            }
            else
            {
                ret += "," + fld.getColname() + (fld.alias != null ? " " + fld.alias : "");
            }
        }

        return ret;
    }

    /**
     * 取空间数据列
     *
     * @param alias  表别名
     * @param dbtype 数据库类型
     * @return String
     * @throws Exception        异常
     */
    public static String getGeomCol(String alias, int dbtype)
    {
        String col = null;
        switch (dbtype)
        {
            case CxConsts.DB_ORACLE:
                col = "SDO_UTIL.TO_WKTGEOMETRY(" + alias + "geom)";
                break;
            case CxConsts.DB_MYSQL:
            case CxConsts.DB_POSTGRESQL:
                col = "ST_AsText(" + alias + "geom)";
                break;
            case CxConsts.DB_DM:
                col = "dmgeo.ST_AsText(" + alias + "geom)";
                break;
            case CxConsts.DB_MSSQL:
                col = alias + "geom.STAsText()";
                break;
        }
        return col;
    }

    //联合查询-ORDER BY,防SQL注入
    public static boolean filterOrderby(String orderby, CxUnionTables tables) throws Exception
    {
        String[]     arr1 = orderby.split(CxConsts.defSep);
        String[]     arr2, arr3;
        CxUnionTable tab;
        int          i;

        for (i = 0; i < arr1.length; i++)
        {
            arr2 = arr1[i].split(" ");

            if (arr2.length < 1 || arr2.length > 2)
                return false;
            if (arr2.length == 2)
            {
                if (arr2[1].compareToIgnoreCase("ASC") != 0 && arr2[1].compareToIgnoreCase("DESC") != 0)
                    return false;
            }

            arr3 = arr2[0].split("\\.");
            if (arr3.length == 1)                                //单表
            {
                //根据别名找表
                tab = tables.get("");
                if (tab == null)
                    return false;

                //判断是不是他的列
                if (arr3[0].compareToIgnoreCase(CxKeys.id) == 0)
                    continue;
                if (!tables.hasField(tab, arr3[0]))
                    return false;
            }
            else if (arr3.length == 2)                            //多表
            {
                //根据别名找表
                tab = tables.get(arr3[0]);
                if (tab == null)
                    return false;

                //判断是不是他的列
                if (arr3[1].compareToIgnoreCase(CxKeys.id) == 0)
                    continue;
                if (!tables.hasField(tab, arr3[1]))
                    return false;
            }
            else
                return false;
        }

        return true;
    }

    /**
     * 构造IN()的参数，在两边增加'',强制转换成字符串
     *
     * @param value 值
     * @return 转换后字符串
     * @throws Exception 异常
     */
    public static String paramIn(String value) throws Exception
    {
        if (value.indexOf("'") >= 0 || value.indexOf(" ") >= 0)
            throw new Exception(CxErrors.errParam + CxConsts.MINUS + value);
        return "'" + value.replaceAll(CxConsts.defSep, "','") + "'";
    }

    /**
     * 将SQL中指定标识符替换成具体的值
     *
     * @param vals   值
     * @param sql    SQL
     * @param symbol 要替换的标识符
     * @return 替换后的SQL字符串
     * @throws Exception 异常
     */
    public static String replace(String vals, String sql, String symbol) throws Exception
    {
        if (!CxValueUtil.isEmpty(vals))
        {
            String[] es = vals.split(CxConsts.SIMICOLON);

            for (int i = 0; i < es.length; i++)
            {
                sql = sql.replaceFirst(symbol, es[i]);
            }
        }
        else
        {
            sql = sql.replace(symbol, "");
        }

        return sql;
    }
}
